<?php
namespace app\common\model;
class Node extends Base{
	/**
	 * 获取所有节点（并且进行分组）
	 * @param  array  $where 条件
	 * @return array
	 */
	function getNodes($where=[]){
		$list=$this->readAll($where)->toArray();
        $list=node_merge($list); 
		return $list;
	}
    /**
     * 清除无效的权限节点
     * @return integer
     */
    function cleanNodes(){
        $list=$this->readAll(['action'=>'0'],0,['field'=>'id']);
        $ids=[];
        foreach ($list as $v) {
            $hasChild=$this->where(['pid'=>$v['id']])->count();
            if(!$hasChild){
                $ids[]=$v['id'];
            }
        }
        return $this->del(['id'=>['id','in',$ids]]);
    }
	/**
	 * #这是标题#{这是说明}
	 * 初始化节点信息(查找特定模块中如上的注释作为节点)
	 * @param  string $module 模块
	 * @return void
	 */
    function initNodes($module=null){
    	if(is_null($module)){
    		$module=request()->module();
    	}
    	$ds=DIRECTORY_SEPARATOR;
    	$namespace='\\'.env('APP_NAMESPACE').'\\'.$module.'\\controller\\';
    	$path=env('app_path').$module.$ds.'controller'.$ds;
    	$rs=read_files($path);
    	$exclude_controller=config('auth.exclude_controller');
    	$data=[];
        $module_id=$this->getModuleId($module);
    	foreach($rs['file'] as $k => $v){
    		$classname=preg_replace("/\.php$/",'',$v);
    		$controller=strtolower($classname);
    		if(in_array($controller,$exclude_controller)){
    			continue;
    		}
    		$class=$namespace.$classname;
    		$refclass= new \ReflectionClass($class);
    		$row=$this->getMethods($refclass,$module,$controller,$module_id);
    		if(!empty($row)){
    			$data=array_merge($data,$row);
    		}
    	}
    	$this->updateNodes($data,$module);
    }
    /**
     * 获取父级模块的ID
     * @param  string $classDoc   控制器类的注释
     * @param  string $module     模块名称
     * @param  string $controller 控制器名称
     * @return integer
     */
    private function getModuleId($module){
        $has=$this->read(['name'=>$module],'id');
        if(count($has)){
            return $has['id'];
        }else{
            $add=$this->add([
                'title'=>"模块({$module})",
                'name'=>$module,
                'module'=>$module,
                'controller'=>0,
                'action'=>0
            ]);
            return $add['id'];
        }
    }
    /**
     * 获取父级控制器的ID
     * @param  string $classDoc   控制器类的注释
     * @param  string $module     模块名称
     * @param  string $controller 控制器名称
     * @return integer
     */
    private function getClassId($classDoc,$module,$controller,$module_id){
        $rs=$this->formatComment($classDoc);
        $name=$module.'/'.$controller;
        $has=$this->read(['pid'=>$module_id,'name'=>$name],'id,title,remark');
        if(empty($rs)){
            if(count($has)){
                return $has['id'];
            }else{
                $add=$this->add([
                    'pid'=>$module_id,
                    'title'=>"控制器({$controller})",
                    'name'=>$name,
                    'module'=>$module,
                    'controller'=>$controller,
                    'action'=>0
                ]);
                return $add['id'];
            }
        }else{
            if(count($has)){
                if($has['title']!==$rs['title']||$has['remark']!==$rs['remark']){
                    $this->edit(['id'=>$has['id'],'title'=>$rs['title'],'remark'=>$rs['remark']]);
                }
                return $has['id'];
            }else{
                $add=$this->add([
                    'pid'=>$module_id,
                    'title'=>$rs['title'],
                    'remark'=>$rs['remark'],
                    'name'=>$name,
                    'module'=>$module,
                    'controller'=>$controller,
                    'action'=>0
                ]);
                return $add['id'];
            }
        }
    }
    //读取类方法
    private function getMethods($refclass,$module,$controller,$module_id){
        $methods = $refclass->getMethods();
        $rs=[];
        if($methods){
            $classDoc=$refclass->getDocComment();
        	$prefix=$module.'/'.$controller.'/';
            foreach($methods as $method){
                $doc=$this->formatComment($method->getDocComment());
                if(!empty($doc)){
                    $pid=$this->getClassId($classDoc,$module,$controller,$module_id);
                	$action=strtolower($method->getName());
                	array_push($rs,[
                		'module'=>$module,
                		'controller'=>$controller,
                        'action'=>$action,
                		'pid'=>$pid,
                		'name'=>$prefix.$action,
                		'title'=>$doc['title'],
                		'remark'=>$doc['remark'],
                	]);
                }
            }
        }
        return $rs;
    }
    /**
     * 更新节点信息
     * @param  array $data 所有节点信息数组 来源：$this->initNodes();
     * @return void
     */
    private function updateNodes($data,$module){
    	if(empty($data)){
    		$this->del(['module'=>$module,'id'=>['id','>',0]]);
    		return;
    	}
    	$i=$this->where(['module'=>$module])->max('i');
    	$updateData=[];
    	$addData=[];
    	foreach($data as $v){
    		$has=$this->read(['name'=>$v['name']],'id,i');
    		if($has&&$has['i']===$i){
    			$v['id']=$has['id'];
    			$v['i']=$i+1;
    			$updateData[]=$v;
    		}elseif($has){
    			
    		}else{
    			$v['i']=$i+1;
    			$addData[]=$v;
    		}
    	}

    	if(!empty($updateData)){
    		$this->edit($updateData);
    	}
    	if(!empty($addData)){
    		$this->add($addData);
    	}
    	$this->del(['module'=>$module,'action'=>['action','neq',0],'i'=>['i','neq',$i+1]]);
    }
    /**
     * 格式化注释内容
     * @param  string $comment 文本
     * @return array
     */
    private function formatComment($comment){
        preg_match("/(?:#)(.*)(?:#)/i",$comment,$title);
        $rs=[];
        if(isset($title[1])){
        	$rs['title']=$title[1];
	        preg_match("/(?:#{)(.*)(?:})/i",$comment,$remark);
        	if(isset($remark[1])){
        		$rs['remark']=$remark[1];
        	}else{
                $rs['remark']='';
        	}
        }
        return $rs;
    }
}
